/**
 * @param Any ctx
 * @param Core.Storage.Configuration storage
 */
Core.Storage.ValueResolver = function(ctx, storage, observable) {
	this.ctx = ctx;
	this.storage = storage;
	this.observable = observable;
	this.pathr = new Core.Storage.PathResolver(this, ctx);
	
};

Core.Storage.ValueResolver.prototype = {
	
	/**
	 * Returns the value from underlying storage.
	 * Evaluates the value if function forced to evaluate.
	 * 
	 * @param String path
	 * @param Core.Storage.Trace trace - tracing object or null.
	 * @param Boolean fe - force to evaluate type:"function" if set to true. 
	 */
	get: function(raw, trace, fe) {
		var path = this.pathr.evaluate(raw, trace);

		if(/^\.\./.test(path)) { return this._getGlobally(path.substr(2), trace, fe); }
		if(/^\./.test(path)) { return this._getLocally(path.substr(1), trace, fe); }
		
		throw new Error("Path '"+ path +"' does not have any leading dots.");
	},
	
	/**
	 * Returns the value from global storage.
	 * Evaluates the value if function forced to evaluate.
	 * 
	 * @param String path - trimmed out of dots global path.
	 * @param Core.Storage.Trace trace - tracing object or null.
	 * @param Boolean fe - force to evaluate type:"function" if set to true. 
	 */
	_getGlobally: function(path, trace, fe) {
		if(trace) { trace.track(path, Core.Storage); }
		return this.evaluate(Core.Storage.get(path), fe);
	},
	
	/**
	 * Returns the value from configuration local storage.
	 * Evaluates the value if function forced to evaluate.
	 * 
	 * @param String path - trimmed out of dots global path.
	 * @param Core.Storage.Trace trace - tracing object or null.
	 * @param Boolean fe - force to evaluate type:"function" if set to true. 
	 */
	_getLocally: function(path, trace, fe) {
		var head = path.shift("."), 
			tail = path.substr(head.length+1);

		if(trace && this.observable) { trace.track(path, this.observable); }
		return this.evaluate(this.storage.get(head), fe, tail);
	},
	
	/**
	 * Evaluates the value into final variable.
	 * Handles primitives & function-like values.
	 * 
	 * @param Any v - value
	 * @param Boolean fe - force to evaluate type:"function" if set to true.
	 * @param String tail - value subpath or null.
	 */
	evaluate: function(v, fe, tail) {
		if(tail) {
			if(Lang.isObject(v) || Lang.isArray(v)) { v = Object.get(v, tail.split(".")); }
			else { throw new Error("Can't retrieve subpath '" + tail + "' from primitive."); }
		}
		
		if(Lang.isFunction(v) && fe) {
			Core.assert(v.length === 0, "Function can't contain any declared arguments.");
			return this.evaluate(v.call(this.ctx), fe);
		}
		return v;
	}
};